package com.wxd.woff.table.glyf;

import java.io.IOException;
import java.util.Arrays;

import com.wxd.woff.AbstractOTFDataStream;

/**
 * Simple Glyph Description Created with IntelliJ IDEA.
 *
 * @author: wangxindong
 * @date: 2018/9/2-10:39
 */
public class GlyfSimpleDescript extends AbstractGlyfDescript {

	private int[] endPtsOfContours;
	private byte[] flags;
	private short[] xCoordinates;
	private short[] yCoordinates;
	private final int pointCount;

	/**
	 * Simple Glyph Description
	 *
	 * @param numberOfContours
	 * @param data
	 */
	public GlyfSimpleDescript(int numberOfContours, AbstractOTFDataStream data, short x0) throws IOException {
		super(numberOfContours, data);

		if (numberOfContours == 0) {
			pointCount = 0;
			return;
		}
		endPtsOfContours = data.readUnsignedShortArray(numberOfContours);

		int lastEndPt = endPtsOfContours[numberOfContours - 1];
		if (numberOfContours == 1 && lastEndPt == 65535) {
			pointCount = 0;
			return;
		}
		pointCount = lastEndPt + 1;

		flags = new byte[pointCount];
		xCoordinates = new short[pointCount];
		yCoordinates = new short[pointCount];

		int instructionCount = data.readUnsignedShort();
		readInstructions(data, instructionCount);
		readFlags(pointCount, data);
		readCoords(pointCount, data, x0);
	}

	private void readCoords(int count, AbstractOTFDataStream data, short x0) throws IOException {
		short x = x0;
		short y = 0;
		for (int i = 0; i < count; i++) {
			if ((flags[i] & X_DUAL) != 0) {
				if ((flags[i] & X_SHORT_VECTOR) != 0) {
					x += (short) data.readUnsignedByte();
				}
			} else {
				if ((flags[i] & X_SHORT_VECTOR) != 0) {
					x += (short) -((short) data.readUnsignedByte());
				} else {
					x += data.readSignedShort();
				}
			}
			xCoordinates[i] = x;
		}

		for (int i = 0; i < count; i++) {
			if ((flags[i] & Y_DUAL) != 0) {
				if ((flags[i] & Y_SHORT_VECTOR) != 0) {
					y += (short) data.readUnsignedByte();
				}
			} else {
				if ((flags[i] & Y_SHORT_VECTOR) != 0) {
					y += (short) -((short) data.readUnsignedByte());
				} else {
					y += data.readSignedShort();
				}
			}
			yCoordinates[i] = y;
		}
	}

	private void readFlags(int flagCount, AbstractOTFDataStream data) throws IOException {
		for (int index = 0; index < flagCount; index++) {
			flags[index] = (byte) data.readUnsignedByte();
			if ((flags[index] & REPEAT) != 0) {
				int repeats = data.readUnsignedByte();
				for (int i = 1; i <= repeats && index + i < flags.length; i++) {
					flags[index + i] = flags[index];
				}
				index += repeats;
			}
		}
	}

	@Override
	public Point[] getPoint() {
		GlyphRenderer renderer = new GlyphRenderer(this);
		return renderer.describe();
	}

	@Override
	public int getEndPtOfContours(int i) {
		return endPtsOfContours[i];
	}

	@Override
	public byte getFlags(int i) {
		return flags[i];
	}

	@Override
	public short getXCoordinate(int i) {
		return xCoordinates[i];
	}

	@Override
	public short getYCoordinate(int i) {
		return yCoordinates[i];
	}

	@Override
	public int getPointCount() {
		return pointCount;
	}

	@Override
	public boolean isComposite() {
		return false;
	}

	@Override
	public String toString() {
		return super.toString() + "GlyfSimpleDescript{" + "endPtsOfContours=" + Arrays.toString(endPtsOfContours)
				+ ", flags=" + Arrays.toString(flags) + ", xCoordinates=" + Arrays.toString(xCoordinates)
				+ ", yCoordinates=" + Arrays.toString(yCoordinates) + ", pointCount=" + pointCount + '}';
	}
}
